﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
//using System.Linq.Expressions;
//using Microsoft.VisualStudio.TestTools.UnitTesting;
#if NET_2_0
using RaisingStudio.Linq;
#endif
using RaisingStudio.Data.Linq;
using RaisingStudio.Data.Entities;
using RaisingStudio.Data.Providers;
using RaisingStudio.Data;
using NUnit.Framework;

namespace LinqTest
{
    /// <summary>
    /// UnitTest1 的摘要说明
    /// </summary>
    [TestFixture]
    public class UnitTest1
    {
        #region 附加测试属性
        //
        // 编写测试时，还可使用以下附加属性:
        //
        // 在运行类中的第一个测试之前使用 ClassInitialize 运行代码
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // 在类中的所有测试都已运行之后使用 ClassCleanup 运行代码
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // 在运行每个测试之前，使用 TestInitialize 来运行代码
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // 在每个测试运行完之后，使用 TestCleanup 来运行代码
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        private DataContext dc;
        private List<int> issueList;

        public const string ISSUETITLE_FORTEST = "Issue Title for UnitTest";

        private void CreateDataContext()
        {
            this.dc = new DataContext();
            this.dc.Log = System.Console.Out;
        }

        private void InsertDummyData()
        {
            this.issueList = new List<int>();
            try
            {
                this.dc.BeginTransaction();
                try
                {
                    Issue issue = new Issue();
                    issue.CreateTime = System.DateTime.Now;
                    issue.Description = "Issue for UnitTest.";
                    issue.IssueType = IssueType.Issue;
                    issue.Locked = false;
                    issue.Owner = "sa";
                    issue.Progress = 10;
                    issue.Status = IssueStatus.New;
                    issue.Title = ISSUETITLE_FORTEST;
                    this.dc.Insert<Issue>(issue);
                    this.issueList.Add(Convert.ToInt32(this.dc.GetMax<Issue>(Issue._.IssueID)));

                    Issue issue2 = new Issue();
                    issue2.CreateTime = System.DateTime.Now;
                    issue2.Description = "Issue2 for UnitTest.";
                    issue2.Progress = 20.34M;
                    issue2.Status = IssueStatus.Fixed;
                    issue2.Title = ISSUETITLE_FORTEST;
                    this.dc.Insert<Issue>(issue2);
                    this.issueList.Add(Convert.ToInt32(this.dc.GetMax<Issue>(Issue._.IssueID)));

                    this.dc.CommitTransaction();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex);
                    this.dc.RollbackTransaction();
                    throw;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                throw;
            }
        }

        private void ClearDummyData()
        {
            if (this.dc != null)
            {
                try
                {
                    this.dc.BeginTransaction();
                    try
                    {
                        foreach (int issueID in this.issueList)
                        {
                            this.dc.Delete<Issue>(issueID);
                        }

                        this.dc.CommitTransaction();
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex);
                        this.dc.RollbackTransaction();
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex);
                    throw;
                }
            }
        }

        public UnitTest1()
        {
            CreateDataContext();
        }

        ~UnitTest1()
        {
            this.dc = null;
        }

        [TestFixtureSetUp]
        public void TestCaseSetup()
        {
            InsertDummyData();
        }

        [TestFixtureTearDown]
        public void TestCaseTearDown()
        {
            ClearDummyData();
        }

        [SetUp]
        public void Init()
        {
        }

        [TearDown]
        public void CleanUp()
        {
        }

        [Test]
        public void Test1()
        {
            Assert.IsNotNull(this.dc);
            Assert.IsNotNull(this.dc.Connection);
            Assert.IsNotNull(this.dc.Database);
            Assert.IsNotNull(this.dc.Provider);
            Assert.IsNotNull(this.dc.LogManager);

            Assert.IsTrue(this.dc.GetCount<Issue>() > 0);
        }


        [Test]
        public void TestMethod1()
        {
            QueryableData<Issue> issues = new QueryableData<Issue>(dc);
            var il = from s in issues where s.IssueID > 0 select s;
            foreach (var issue in il)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var il2 = from s in issues where s.IssueID > 0 && s.Title == ISSUETITLE_FORTEST select s;
            foreach (var i in il2)
            {
                Assert.IsTrue(i.IssueID > 0);
                Assert.IsTrue(i.Title == ISSUETITLE_FORTEST);
            }
        }

        [Test]
        public void Test2()
        {
            QueryableData<Issue> issues = new QueryableData<Issue>(dc);
            var il = from s in issues
                     where s.IssueID > 0 && s.Title != ISSUETITLE_FORTEST || (bool)s.Locked == true
                     select s;
            foreach (var issue in il)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var il2 = from s in issues
                      where s.IssueID > 0
                      orderby s.IssueID descending
                      select s;
            foreach (var issue in il2)
            {
                Assert.IsTrue(issue.IssueID > 0);
            }

            var a = (from s in (this.dc.GetQueryableData<Issue>()) select s);
            Assert.IsNotNull(a);
            // TODO:
            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetCount<Issue>(a));
            Assert.AreEqual(this.dc.GetCount<Issue>(), a.Count());

            var b = (from s in (new RaisingStudio.Data.Expressions.QueryExpression<Issue>()) select s);
            System.Data.DataTable dt1 = this.dc.QueryForDataTable<Issue>(b);
            Assert.IsNotNull(dt1);
            Assert.AreEqual(this.dc.GetCount<Issue>(), dt1.Rows.Count);

            var c = (from s in (this.dc.GetExpressionData<_Issue, Issue>(Issue._)) select s);
            System.Data.DataTable dt2 = c.QueryForDataTable();
            Assert.IsNotNull(dt2);
            Assert.AreEqual(this.dc.GetCount<Issue>(), dt2.Rows.Count);

            var dataTable = this.dc.QueryForDataTable<Issue>(Issue._, Issue._);
            var issueList = (this.dc.GetExpressionData<_Issue, Issue>((from s in Issue._ select s))).QueryForList<Issue>();
            Assert.IsNotNull(issueList);
            Assert.AreEqual(dataTable.Rows.Count, issueList.Count);
            Assert.IsNotNull(issueList[0]);
            Assert.IsNotNull(issueList[0].Title);
        }

        [Test]
        public void Test3()
        {
            int maxID = this.dc.GetMax<Issue, int>(from s in Issue._ select s.IssueID);
            var q = (IQueryableData)(from s in this.dc.GetQueryableData<Issue>() select s.IssueID);
            Assert.AreEqual(maxID, q.GetMax<Issue, int>());
            decimal originalProgress = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == maxID select s.Progress).Progress.Value;
            int result = this.dc.UpdateByQuery<Issue>(new Issue { Progress = originalProgress + 1 }, (from s in Issue._ where s.IssueID == maxID select s.Progress));
            Assert.AreEqual(1, result);
            decimal currrentProgress = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == s.IssueID.Max select s.Progress).Progress.Value;
            Assert.AreEqual(originalProgress + 1, currrentProgress);
        }

        [Test]
        public void Test4()
        {
            var q = from s in this.dc.GetExpressionData<_Issue, Issue>(Issue._)
                    where s.Title == ISSUETITLE_FORTEST
                    select s;
            int count = 0;
            foreach (Issue issue in q)
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, issue.Title);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);

            count = 0;
            foreach (var issue in q.Query(0, 1))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, issue.Title);
                count++;
            }
            Assert.AreEqual(1, count);
        }

        [Test]
        public void Test5()
        {
            // TODO:            
            var i = this.dc.GetQueryableData<Issue>();
            // TODO: partial column in Queryable LINQ.                      
            foreach (var item in from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }

            foreach (var item in this.dc.Query<Issue>(from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title }))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
          
            var q = this.dc.GetExpressionData<_Issue, Issue>(Issue._);
            int count = 0;
            foreach (var item in from s in q where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);

            decimal value = 10;
            count = 0;
            foreach (var item in from s in q where s.Progress >= value select s.Progress)
            {
                Assert.GreaterOrEqual(item.Progress, value);
                count++;
            }
            Assert.GreaterOrEqual(count, 1);
        }

        [Test]
        public void Test6()
        {
            var q = new ExpressionData<_Issue, Issue>(this.dc, Issue._);
            Assert.AreEqual(this.dc.GetMax<Issue>(Issue._.Progress), (from s in q select s.Progress).GetMax<Issue, decimal>());

            var q2 = (from s in (new ExpressionData<_Issue, Issue>(this.dc, Issue._)) select s.Progress);
            Assert.AreEqual(this.dc.GetMax<Issue>(Issue._.Progress), q2.GetMax());
        }

        [Test]
        public void Test7()
        {
            // TODO: GetData, Delete, Exists ...
            Assert.IsTrue(this.dc.Exists<Issue>(this.issueList[0]));
            Assert.IsTrue(this.dc.ExistsByQuery<Issue>(from s in Issue._ where s.Title == ISSUETITLE_FORTEST select s));

            // TODO:
            Assert.IsTrue(this.dc.ExistsByQuery<Issue>(s => s.Title == ISSUETITLE_FORTEST));
            Assert.IsTrue((from s in new ExpressionData<_Issue, Issue>(this.dc, Issue._) where s.Title == ISSUETITLE_FORTEST select s).Exists());
        }

        [Test]
        public void Test8()
        {
            // TODO: 
            decimal avg = Convert.ToDecimal(this.dc.GetAvg<Issue>(s => s.Progress));
            decimal avg2 = this.dc.GetAvg<Issue, decimal>(from s in Issue._ select s.Progress);
            Assert.AreEqual(this.dc.GetAvg<Issue>(Issue._.Progress), avg);
            Assert.AreEqual(avg, avg2);
        }

        [Test]
        public void Test9()
        {
            int count = this.dc.GetCount<Issue>();
            Assert.GreaterOrEqual(count, 1);

            count = this.dc.GetCount<Issue>(s => s.IssueID == this.issueList[0]);
            Assert.AreEqual(1, count);

            count = this.dc.GetCount<Issue>(from s in Issue._ where s.IssueID == this.issueList[0] | s.Title == ISSUETITLE_FORTEST select s);
            Assert.GreaterOrEqual(count, 1);

            var q = new ExpressionData<_Issue, Issue>(this.dc, Issue._);
            count = (from s in q where s.IssueID == this.issueList[0] | s.Title == ISSUETITLE_FORTEST select s).GetCount();
            Assert.GreaterOrEqual(count, 1);
        }

        [Test]
        public void Test10()
        {
            // TODO:
            Issue issue = this.dc.QueryForSingle<Issue>(s => s.IssueID == this.issueList[0]);
            //Issue issue = this.dc.GetData<Issue>(this.issueList[0]);
            var i2 = this.dc.QueryForSingle<Issue>(from s in Issue._ where s.IssueID == this.issueList[0] select s);
            Assert.AreEqual(issue.IssueID, i2.IssueID);
        }


        [Test]
        public void Test14()
        {
            var q = this.dc.Query<Issue>(from s in Issue._ orderby s.IssueID select s);
            int count = 0;
            int issueID = 0;
            foreach (var issue in q)
            {
                Assert.Greater(issue.IssueID, issueID);
                issueID = issue.IssueID;
                count++;
            }
            Assert.Greater(count, 0);

            var q2 = (from s in (new ExpressionData<_Issue, Issue>(this.dc, Issue._)) orderby s.IssueID descending select s);
            count = 0;
            foreach (var issue in q2)
            {
                Assert.LessOrEqual(issue.IssueID, issueID);
                issueID = issue.IssueID;
                count++;
            }
            Assert.Greater(count, 0);
        }


        [Test]
        public void TestMethod2()
        {
            var a = (from s in (this.dc.GetQueryableData<Issue>()) select s);
            Assert.IsNotNull(a);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetCount<Issue>(), a.Count());
            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetCount<Issue>(a));

            Assert.AreEqual(this.dc.GetCount<Issue>(), this.dc.GetQueryableData<Issue>().Count());

            var b = (from s in (this.dc.GetQueryableData<Issue>()) where s.IssueID == this.issueList[0] select s);
            Assert.AreEqual(this.dc.GetCount<Issue>(Issue._.IssueID == this.issueList[0]), b.Count());

            var i = this.dc.GetQueryableData<Issue>();
            // TODO: partial column in Queryable LINQ.                      
            foreach (var item in from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title })
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
            foreach (var item in this.dc.Query<Issue>(from s in i where s.Title == ISSUETITLE_FORTEST select new { s.IssueID, s.Title }))
            {
                Assert.AreEqual(ISSUETITLE_FORTEST, item.Title);
            }
        }

        [Test]
        public void TestMethod3()
        {
            var b = (from s in (this.dc.GetQueryableData<Issue>()) select s.IssueID);
            Assert.IsNotNull(b);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetAvg<Issue, double>(b), b.Average());
            Assert.AreEqual(this.dc.GetMax<Issue, int>(b), b.Max());
            Assert.AreEqual(this.dc.GetMin<Issue, int>(b), b.Min());
            Assert.AreEqual(this.dc.GetSum<Issue, int>(b), b.Sum());

            var a = (from s in (this.dc.GetQueryableData<Issue>()) where s.IssueID > 0 select s.IssueID);
            Assert.IsNotNull(a);
            // TODO: function for Queryable LINQ.
            Assert.AreEqual(this.dc.GetAvg<Issue, double>(a), a.Average());
            Assert.AreEqual(this.dc.GetMax<Issue, int>(a), a.Max());
            Assert.AreEqual(this.dc.GetMin<Issue, int>(a), a.Min());
            Assert.AreEqual(this.dc.GetSum<Issue, int>(a), a.Sum());
        }
    }
}
